#ifndef EXPRESSIONPARSER_H
#define EXPRESSIONPARSER_H

#include "FileContentBase.h"
#include "ExpressionPreprocessed.h"

#include <wx/string.h>
#include <wx/arrstr.h>

#include <map>

namespace Expression {


  class Parser {
    public:


      Parser();


      ~Parser();


      bool Parse( const wxString& expression, Preprocessed& output );


      inline wxString ParseErrorDesc( int& pos ) { pos = m_ErrorPos; return m_ErrorDesc; }


      wxArrayString GetSuggestions( const wxString& expression, int pos );


      static wxString GetHelpString();

    private:

      wxString m_ErrorDesc;           ///< \brief Error description if parsing failed
      int      m_ErrorPos;
      Preprocessed* m_Output;
      const wxChar* m_StartPos;       ///< \brief Beginning of the parse buffer
      const wxChar* m_CurrentPos;
      typedef Operation::modifier resType;

      static const resType resNone        = Operation::modNone;
      static const resType resSignedInt   = Operation::modLongLong;
      static const resType resUnsignedInt = Operation::modQword;
      static const resType resFloat       = Operation::modLongDouble;


      struct ParseTree {
        resType    m_OutType;       ///< \brief Produced type
        resType    m_InType;        ///< \brief Required type of inputs
        Operation  m_Op;            ///< \brief Executed operation
        ParseTree* m_FirstSub;      ///< \brief First input tree (NULL if no first input)
        ParseTree* m_SecondSub;     ///< \brief Second input tree (NULL if no second input)
        Value      m_ArgValue;


        inline ParseTree()
          : m_OutType( Operation::modNone )
          , m_InType( Operation::modNone )
          , m_FirstSub( 0 )
          , m_SecondSub( 0 )
          , m_ArgValue( 0 ) {}


        inline ~ParseTree() {
          delete m_FirstSub;
          delete m_SecondSub;
          m_FirstSub = m_SecondSub = 0;
        }
      };

      std::vector< ParseTree* > m_TreeStack;      ///< \brief Current parsing tree
      std::map< Value, int >    m_ArgMap;

      void Parse();


      void Expression();


      void Add();


      void Mult();


      void Unary();


      void Primary();


      bool Number();


      bool Const();


      bool Memory();


      bool Function();


      inline void AddOp(
        int subArgs,
        Operation::opCode op,
        resType producedType,
        resType argumentsType,
        Operation::modifier mod1,
        Operation::modifier mod2 = Operation::modNone,
        short opConst = 0 );


      inline void AddOp1( Operation::opCode op, resType type );


      inline void AddOp1( Operation::opCode op );


      inline void AddOp2( Operation::opCode op, resType type );


      inline void AddOp2( Operation::opCode op );


      template< class T >
      inline void ConstArg( T value, resType type );


      inline ParseTree* PopTreeStack() {
        assert( !m_TreeStack.empty() );
        ParseTree* ret = m_TreeStack.back();
        m_TreeStack.pop_back();
        return ret;
      }


      inline void PushTreeStack( ParseTree* t ) {
        m_TreeStack.push_back( t );
      }


      inline resType TopType( int pos );


      inline resType HigherType2Top();


      inline resType TopAfterNeg();


      inline resType ModResult2Top();


      inline int AddArg( const Value& value );

      inline wxChar Get();
      inline wxChar Get( int shift );

      inline bool Match( wxChar ch );
      inline bool Match( const wxChar* text );
      inline void Require( wxChar ch );
      inline void Require( const wxChar* text );
      inline void EatWhite();
      inline void Next();

      inline void Error( const wxString& desc );

      inline resType HigherType( resType t1, resType m2 );

      void GenerateCode( ParseTree* tree );
      void GenerateCodeAndConvert( ParseTree* tree, resType type );
  };
}

#endif
